2026-09-27 · class-notes, powershell, month-of-lunches, windows, modules, snap-ins, profile-scripts, powershell-gallery
Full class notes for MoL ch. 7: management shells, snap-ins vs modules, module discovery/import, profile scripts, and the PowerShell Gallery.
How these notes were made: the material supplied for this lesson was the chapter's own heading list — "How one shell can do everything", "About product-specific management shells", "Extensions: finding/adding snap-ins", "Extensions: finding/adding modules", "Command conflicts and removal", "On non-Windows OS", "Playing with a new module", "Profile scripts", "Getting modules from the internet", "Common points of confusion" — with an explicit instruction to draft the content from general knowledge rather than a transcript. These notes follow that structure, but the explanations are written from general knowledge of PowerShell's module system, not reproduced or paraphrased from Don Jones and Jeffery Hicks's actual book text, which was not supplied. Worth checking against your own copy of the chapter for their specific wording and examples.
Class notes · Learn Windows PowerShell in a Month of Lunches (3rd ed.), Don Jones and Jeffery Hicks · Chapter 7
Quick reference: the short version of this lesson lives in the Learn PowerShell resource sheets. This follows Chapter 6 (The Pipeline) and shifts focus: rather than what PowerShell can already do, this chapter is about extending what it can do with additional commands.
By the end of these notes you should be able to:
PowerShell's core engine does not, by itself, know how to manage Exchange mailboxes, Azure resources, or SQL Server databases. Instead, PowerShell is built to be extended: vendors and the community ship cmdlets for their own products as add-ons, which you load into an ordinary PowerShell session as needed. The result is that the same shell — the same syntax, the same pipeline, the same help system — works for practically any product that has published a PowerShell extension, rather than needing a completely different tool for every product.
Many products ship with what looks like their own dedicated shell — for
example, an "Exchange Management Shell" shortcut, or a "SQL Server PowerShell"
icon. These are not separate shells with their own engine. They are
ordinary powershell.exe (or pwsh) sessions, launched with a shortcut that
automatically loads that product's extension before you see a prompt.
Exam tip: if you understand this, a "management shell" stops looking like a mysterious separate tool and becomes simply "PowerShell, with one particular extension already loaded" — you could achieve the same result yourself in an ordinary PowerShell window by loading that extension manually.
Snap-ins are the older of the two extension mechanisms, from early
PowerShell versions. A snap-in is a compiled .dll registered with Windows,
providing a set of cmdlets.
Get-PSSnapin -Registered # list snap-ins installed and available to load
Add-PSSnapin <SnapinName> # load a registered snap-in into the session
Get-PSSnapin # list snap-ins currently loaded
Note (beyond this lesson): snap-ins are effectively legacy. They only work in Windows PowerShell (not in cross-platform PowerShell 7/PowerShell Core), and Microsoft's own guidance since PowerShell 2.0 has been to prefer modules for new extensions. You mainly still encounter snap-ins with older products that have not been updated (some legacy Exchange tooling being a well-known example).
Modules are the modern extension mechanism, and almost everything you add to PowerShell today will be a module rather than a snap-in.
Get-Module -ListAvailable # list modules installed on this system
Import-Module <ModuleName> # load a module into the current session
Get-Module # list modules currently loaded
Once a module is imported, the commands it provides behave exactly like built-in cmdlets — same discoverability, same help, same pipeline behaviour.
In the real world: since PowerShell 3.0, you often do not even need to run
Import-Moduleexplicitly. If a command from an installed module is typed at the prompt, PowerShell auto-discovers and auto-loads the module that provides it the first time it is used in a session.
Two different extensions can sometimes provide a command with the same name. When that happens, the most recently imported module's version of the command generally takes precedence.
To avoid a clash deliberately, Import-Module accepts a -Prefix
parameter, which adds a prefix to every noun in that module's commands (so
Get-User from one module could become Get-ContosoUser when imported with
-Prefix Contoso), letting both versions coexist without a naming collision.
To remove a loaded module (and the conflict it may be causing) from the current session:
Remove-Module <ModuleName>
Two different vendor modules, ModuleA and ModuleB, both provide a
Get-Report cmdlet, and you need both loaded at once.
Import-Module ModuleA
Import-Module ModuleB -Prefix B
Get-Report # runs ModuleA's version
Get-BReport # runs ModuleB's version, thanks to the prefix
Both commands are now available side by side, disambiguated by the prefix rather than one silently overriding the other.
PowerShell 7 (built on .NET, and often called PowerShell Core) runs on Linux and macOS as well as Windows. Not every module behaves identically across platforms:
A typical first encounter with an unfamiliar module follows a predictable pattern:
Get-Module -ListAvailable NewModuleName # confirm it's actually installed
Import-Module NewModuleName # load it
Get-Command -Module NewModuleName # see what commands it adds
Get-Help <SomeNewCommand> -Examples # learn one command at a time
This mirrors the general PowerShell discovery habit from earlier chapters — find what's there, then read the help — just applied to a module's commands specifically rather than the whole shell.
Typing Import-Module for the same set of modules every single session gets
tedious. A profile script runs automatically every time PowerShell
starts, and is the natural place to put commands you always want available —
including Import-Module lines for extensions you use constantly.
$PROFILE # shows the path to your personal profile script
Test-Path $PROFILE # check whether it currently exists
If it does not exist yet, you create it (and its containing folder, if needed) and add lines such as:
Import-Module MyFavouriteModule
Note (beyond this lesson):
$PROFILEactually represents one of several possible profile scripts — PowerShell checks scripts scoped to the current user vs all users, and the current host application (the console) vs all hosts.$PROFILEon its own points at the "current user, current host" profile, the one used most often for personal customisation.
Beyond what ships with Windows or a product installer, a huge additional library of community and vendor modules is published to the PowerShell Gallery, and PowerShell's built-in package-management commands can search it and install directly from it:
Find-Module -Name SomeModule # search the Gallery
Install-Module -Name SomeModule # download and install it
Install-Module -Name SomeModule -Scope CurrentUser # install for you only, no admin needed
Once installed this way, the module behaves exactly like any other installed
module — Get-Module -ListAvailable, Import-Module, and so on all work the
same regardless of where the module originally came from.
A few recurring stumbling blocks when working with extensions:
Get-Module -ListAvailable) without being
imported into your current session (actually usable right now,
listed by plain Get-Module). Auto-loading blurs this in practice, but the
distinction still matters when troubleshooting "why can't I use this
command."Add-PSSnapin, not Import-Module) and do
not work at all in PowerShell 7.Install-Module without -Scope CurrentUser
typically installs for all users and requires administrator
rights — a common source of unexpected "access denied" errors for someone
expecting a simple, user-level install.Extending PowerShell with third-party code is, functionally, running someone else's software with your privileges — worth treating with the same care as any other software installation:
-Scope CurrentUser narrows blast radius, not just admin friction.
Installing for the current user only, rather than all users, means a
compromised or malicious module affects one account's profile rather than
every user of the machine — a meaningful containment benefit on a shared or
multi-user system, on top of avoiding the need for elevated rights.Import-Module or arbitrary command added to $PROFILE
executes silently on every future session. Review profile script contents
periodically, and protect write access to profile files the same way you
would protect any other auto-run location.Add-PSSnapin, Get-PSSnapin -Registered) are the legacy
mechanism, Windows-only and largely superseded; modules
(Import-Module, Get-Module -ListAvailable) are the modern standard and
often auto-load on first use since PowerShell 3.0.-Prefix on Import-Module avoids the clash
deliberately; Remove-Module unloads one.$PROFILE points to your personal startup script — put routine
Import-Module lines there to preload extensions automatically.Find-Module,
Install-Module, optionally -Scope CurrentUser).| Term | Meaning |
|---|---|
| Extension | An add-on providing new PowerShell commands. |
| Management shell | PowerShell pre-loaded with one product's extension. |
| Snap-in | Legacy, Windows-only extension mechanism. |
| Module | The modern extension mechanism; cross-platform. |
| Import-Module | Loads a module into the current session. |
| Add-PSSnapin | Loads a registered snap-in into the session. |
| Auto-loading | PowerShell loading a module automatically on first use. |
| -Prefix | Import-Module parameter avoiding command-name clashes. |
| Remove-Module | Unloads a module from the current session. |
| $PROFILE | The path to the current user/host's profile script. |
| Profile script | A script run automatically at PowerShell startup. |
| PowerShell Gallery | The public online repository for modules. |
| Find-Module | Searches the PowerShell Gallery. |
| Install-Module | Downloads and installs a module from the Gallery. |
| Scope (install) | Whether a module installs for the current user or all users. |
| Execution policy | Setting controlling which scripts may run (beyond this lesson). |
Get-PSSnapin -Registered lists them; Add-PSSnapin <name> loads
one. The legacy pair of commands.Import-Module <name> loads one. The modern mechanism.Find-Module to search; Install-Module to download and install.
The Gallery workflow.-Prefix, e.g. Import-Module ModuleB -Prefix B, giving Get-Status and Get-BStatus. Prefix
avoids the clash.$PROFILE) — it runs automatically on every
startup and is a common place for an unexpected auto-run command to
hide. A classic startup-persistence location.